package com.hspedu.seckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hspedu.seckill.mapper.OrderMapper;
import com.hspedu.seckill.pojo.Order;
import com.hspedu.seckill.pojo.SeckillGoods;
import com.hspedu.seckill.pojo.SeckillOrder;
import com.hspedu.seckill.pojo.User;
import com.hspedu.seckill.service.OrderService;
import com.hspedu.seckill.service.SeckillGoodsService;
import com.hspedu.seckill.service.SeckillOrderService;
import com.hspedu.seckill.utils.MD5Util;
import com.hspedu.seckill.utils.UUIDUtil;
import com.hspedu.seckill.vo.GoodsVo;
import lombok.Builder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.concurrent.TimeUnit;


@Service
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
                    implements OrderService{

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private SeckillOrderService seckillOrderService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean checkCaptcha(User user, Long goodsId, String captcha) {
        if(user == null || goodsId < 0 || !StringUtils.hasText(captcha))
            return false;

        String redisCaptcha = (String) redisTemplate.opsForValue().get("captcha:" + user.getId() + ":" + goodsId);

        return captcha.equals(redisCaptcha);

    }

    //生成路径
    @Override
    public String createPath(User user, Long goodsId) {
        String path = MD5Util.md5(UUIDUtil.uuid());
        //seckillPath:userId:goodsId
        redisTemplate.opsForValue().set("seckillPath:" + user.getId() + ":" + goodsId
        ,path,60, TimeUnit.SECONDS);

        return path;
    }

    //校验路径
    @Override
    public boolean checkPath(User user, Long goodsId, String path) {
        if (user == null || goodsId < 0 || !StringUtils.hasText(path))
            return false;

        String redisPath = (String) redisTemplate.opsForValue().
                get("seckillPath:" + user.getId() + ":" + goodsId);

        return path.equals(redisPath);

    }

    //完成秒杀
    @Override
    public Order seckill(User user, GoodsVo goodsVo) {
        /*
         * 消息传到这里的时候，默认有库存，判断库存操作，在Controller判断
         */


        //查询商品，并库存减1
        SeckillGoods goods = seckillGoodsService.
                getOne(new QueryWrapper<SeckillGoods>().eq("goods_id", goodsVo.getId()));


//        goods.setStockCount(goods.getStockCount() - 1);
//        seckillGoodsService.updateById(goods);

        //Mysql默认隔离级别下，会在事务中锁定要更新的行，进行串行操作
        boolean update = seckillGoodsService.update(new UpdateWrapper<SeckillGoods>()
                .setSql("stock_count = stock_count - 1")
                .eq("goods_id", goodsVo.getId())
                .gt("stock_count",0));

        //更新失败，说明没有库存了
        if(!update){
            return null;
        }


        //生成普通订单
        Order order = Order.builder().userId(user.getId())
                .goodsId(goodsVo.getId())
                .deliveryAddrId(0L) //字段无影响
                .goodsName(goodsVo.getGoodsName())
                .goodsCount(1)
                .goodsPrice(goods.getSeckillPrice())
                .orderChannel(1)    //字段无影响
                .status(0)
                .createDate(new Date()) //Now
                .build();

        //存入订单库
        orderMapper.insert(order);

        //生成秒杀订单
        SeckillOrder seckillOrder = SeckillOrder.builder().goodsId(goodsVo.getId())
                .orderId(order.getId())
                .userId(user.getId())
                .build();

        seckillOrderService.save(seckillOrder);

        //秒杀订单存入redis
        redisTemplate.opsForValue()
                .set("order:"+user.getId()+":"+goodsVo.getId(),seckillOrder);

        return order;



    }

}
